package com.supermap.gwfs.datashare.of.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.supermap.gcpp.core.common.UniObject;
import com.supermap.gwfs.datashare.util.CollectionUtil;
import com.supermap.gwfs.datashare.util.Logger;
import org.springframework.stereotype.Service;

/**  
 * @Description: 天气现象
 * @author zhoujian
 * @date 2017-8-27
 * @version V1.0 
 */
@Service
public class WeatherService
{
	
	private Logger logger = Logger.getLogger(this.getClass());
	public Map<String, Map<Integer, String>> weatherPhenomena(Map<String, Map<String, List<Float>>> map , UniObject params , int interval)
	{
		
		Map<String, Map<Integer, String>> stationAndWeather = new HashMap<String, Map<Integer,String>>();
		UniObject statandarObject = params.getObjectsByName("statandar").get(0);
		//判断云状参数
		List<UniObject> etcParam = statandarObject.getObjectsByName("etc");
		//获取降水部分参数
		List<UniObject> rainObject = statandarObject.getObjectsByName("rain");
		//获取雪部分参数
		List<UniObject> snowObject = statandarObject.getObjectsByName("snow");
		//获取
		UniObject weatherParam = params.getObjectsByName("weather").get(0);
		for (String staionId : map.keySet())
		{
			Map<String, List<Float>> elementAndValue = map.get(staionId);
			List<Float> rainList = null;
			List<Float> etcList = null;
			List<Float> pphList = null;
			List<Float> ssmList = null;
			List<Float> hzList = null;
			List<Float> hailList = null;
			List<Float> fogList = null;
//			this.fillData(rainList , etcList , pphList , ssmList , hzList , hailList ,fogList , elementAndValue);
			
			
			for (String element : elementAndValue.keySet())
			{
				switch (element)
				{
				case "ER03":
				case "TPE":
					rainList = elementAndValue.get(element);
					break;
				case "PPH":
					pphList = elementAndValue.get(element);
					break;
				case "ECT":
					etcList = elementAndValue.get(element);
					break;
				case "SSM":
					ssmList = elementAndValue.get(element);
					break;
				case "HZ":
					hzList = elementAndValue.get(element);
					break;
				case "HAIL":
					hailList = elementAndValue.get(element);
					break;
				case "FOG":
					fogList = elementAndValue.get(element);
					break;

				default:
					break;
				}
			}
			
			 /*
			  * 判断云状部分
			  */
			Map<Integer, Integer> cloudCodes = this.cloud(etcList , etcParam, interval);
			/*
			 * 降水部分
			 */
			
			//雷阵雨和冰雹
			Map<Integer , Integer> thundershowerCodes = this.thunderShower(rainList , ssmList ,  hailList , interval);
			//雨夹雪
			Map<Integer , Integer> sleetCodes = this.sleet(rainList , pphList , interval);
			//降水
			Map<Integer, Integer> rainCodes = this.rain(rainList, pphList, rainObject , interval);
			//雪
			Map<Integer, Integer> snowCodes = this.snow(rainList , pphList , snowObject , interval);
			/*
			 * 判断环境天气(暂时只判断雾和霾)
			 */
			//雾
			Map<Integer, Integer> fogCodes = this.fogOrHaze(fogList , interval , "F");
			//霾
			Map<Integer, Integer> hazeCodes = this.fogOrHaze(hzList , interval , "H");
			
			System.out.println(staionId);
			//最后每个时效都会有一个天气现象代码和优先级
			Map<Integer, String> weatherMap = this.weatherBypriority(cloudCodes , thundershowerCodes , sleetCodes , rainCodes , snowCodes , fogCodes , hazeCodes , weatherParam);
			//只选取一个天气
			System.out.println(rainList);	
			
			stationAndWeather.put(staionId, weatherMap);
			
		}
		return stationAndWeather;
	}
	
	/**
	 * 
	 * @Description: 把数据封装到List中
	 * @return void
	 * @throws
	 */
	private void fillData(List<Float> rainList, List<Float> etcList,
			List<Float> pphList, List<Float> ssmList, List<Float> hzList,
			List<Float> hailList, List<Float> fogList,
			Map<String, List<Float>> elementAndValue)
	{

		for (String element : elementAndValue.keySet())
		{
			switch (element)
			{
			case "ER03":
			case "TPE":
				rainList = elementAndValue.get(element);
				break;
			case "PPH":
				pphList = elementAndValue.get(element);
				break;
			case "ECT":
				etcList = elementAndValue.get(element);
				break;
			case "SSM":
				ssmList = elementAndValue.get(element);
				break;
			case "HZ":
				hzList = elementAndValue.get(element);
				break;
			case "HAIL":
				hailList = elementAndValue.get(element);
				break;
			case "FOG":
				fogList = elementAndValue.get(element);
				break;

			default:
				break;
			}
		}
	}
	/**
	 * 
	 * @Description: 根据每个时效的天气现象编码 和优先级  比较产生最后的时效天气现象
	 * @return Map<String,String>
	 * @throws
	 */
	private Map<Integer, String> weatherBypriority(
			Map<Integer, Integer> cloudCodes,
			Map<Integer, Integer> thundershowerCodes,
			Map<Integer, Integer> sleetCodes, Map<Integer, Integer> rainCodes,
			Map<Integer, Integer> snowCodes, Map<Integer, Integer> fogCodes,
			Map<Integer, Integer> hazeCodes, UniObject weatherParam)
	{
		Map<Integer, String> validAndWeather = new HashMap<Integer,String>();
		try
		{
			for (Integer valid : cloudCodes.keySet())
			{
				int cloudCode = cloudCodes == null ? 999 :cloudCodes.get(valid);	//云状天气编码
				int showerCode = thundershowerCodes == null ? 999 :thundershowerCodes.get(valid);//雷阵雨或者冰雹天气编码
				int sleetcode = sleetCodes == null ? 999 :sleetCodes.get(valid);	//雨夹雪天气编码
				int rainCode = rainCodes == null ? 999 :rainCodes.get(valid);	//降雨天气编码
				int snowCode = snowCodes == null ? 999 :snowCodes.get(valid);	//降雪天气编码
				int fogCode = fogCodes == null ? 999 :fogCodes.get(valid);		//雾天气编码
				int hazeCode = hazeCodes == null ? 999 :hazeCodes.get(valid);	//霾天气编码
				
				
				String weather = this.weatherByCodeAndPriority(cloudCode , showerCode , sleetcode , rainCode , snowCode , fogCode , hazeCode , weatherParam);
				validAndWeather.put(valid, weather);
				
			}
		}
		catch (Exception e)
		{
			logger.error("Get weather phenomena exception , this exception is : " + e);
		}
		
		return validAndWeather;
	}
	private String weatherByCodeAndPriority(int cloudCode, int showerCode,
			int sleetcode, int rainCode, int snowCode, int fogCode,
			int hazeCode, UniObject weatherParam)
	{
		String weather = null;
		try
		{
			Map<Integer, Integer> codeAndPriority = new HashMap<Integer, Integer>();
			//TODO 非空判断
			codeAndPriority.put(cloudCode, weatherParam.getObjectsByName(String.format("%02d", cloudCode)).get(0).getIntegerValue("weatherPriority"));
			codeAndPriority.put(showerCode, weatherParam.getObjectsByName(String.format("%02d", showerCode)).get(0).getIntegerValue("weatherPriority"));
			codeAndPriority.put(sleetcode, weatherParam.getObjectsByName(String.format("%02d", sleetcode)).get(0).getIntegerValue("weatherPriority"));
			codeAndPriority.put(rainCode, weatherParam.getObjectsByName(String.format("%02d", rainCode)).get(0).getIntegerValue("weatherPriority"));
			codeAndPriority.put(snowCode, weatherParam.getObjectsByName(String.format("%02d", snowCode)).get(0).getIntegerValue("weatherPriority"));
			codeAndPriority.put(fogCode, weatherParam.getObjectsByName(String.format("%02d", fogCode)).get(0).getIntegerValue("weatherPriority"));
			codeAndPriority.put(hazeCode, weatherParam.getObjectsByName(String.format("%02d", hazeCode)).get(0).getIntegerValue("weatherPriority"));
			//获取优先级最高的天气现象编码
			int code = (int)CollectionUtil.getMinkeyByMinValue(codeAndPriority);
			
			weather = weatherParam.getObjectsByName(String.format("%02d", code)).get(0).getStringValue("weather");
		}
		catch (Exception e)
		{
			logger.error("Get weather phenomena by code and priority exception , this exception is : " + e);
		}
		
		return weather;
	}
	/**
	 * 
	 * @Description: 判断一段时间的环境天气现象(雾  霾)
	 * @return Map<Integer,Integer>
	 * @throws
	 */
	private Map<Integer, Integer> fogOrHaze(List<Float> dataList, int interval , String flag)
	{
		Map<Integer, Integer> result = new HashMap<Integer, Integer>();
		
		try
		{
			if (dataList == null)
			{
				logger.error("Haze or fog data is null.");
				return null;
			}
			int length = dataList.size();
			int size = interval / 3;
			
			for (int i = 0; i < length / size; i++)
			{
				result.put((i + 1) * interval, this.fogOrHaze(dataList.subList(i * size, (i + 1) * size) , flag));
			}
		}
		catch (Exception e)
		{
			logger.error("Fog or Haze ("+ flag +") transform to weather phenomena exception , this exception is : " + e);
		}
		return result;
	}
	/**
	 * 
	 * @Description: 单时效的环境现象 雾  霾
	 * 说明：时效中雾预报编码为1,2,3,4,5的其中之一都判断为雾，-1为无   9999缺测
	 * 	         时效中雾预报编码为1,2,3,4的其中之一都判断为霾，-1为无   9999缺测
	 * @return Integer
	 * @throws
	 */
	private Integer fogOrHaze(List<Float> datas , String flag)
	{
		int code = 999;
		try
		{
			if (datas.contains(1f) || datas.contains(2f) || datas.contains(3f) || datas.contains(4f)|| datas.contains(5f))
			{
				if ("F".equals(flag))
				{
					code = 18;
				}else {
					code = 53;
				}
			}
		}
		catch (Exception e)
		{
			logger.error("Singn valid FOG or HAZE (" + flag + ") transform to weather phenomena exception , this exception is : " + e);
		}
		
		return code;
	}
	/**
	 * 
	 * @Description: 降雪
	 * 说明：12小时内，降水相态为3的时段的降水量R,使用R来确定雪的量级
	 * @return Map<Integer,Integer>
	 * @throws
	 */
	private Map<Integer, Integer> snow(List<Float> rain, List<Float> pph, List<UniObject> snowObject , int interval)
	{
		
		Map<Integer, Integer> result = null;//new HashMap<Integer, Integer>();
		
		try
		{
			result = new HashMap<Integer, Integer>();
			if (rain == null || pph == null || snowObject == null)
			{
				logger.error("rain or pph or snowObject is null.");
				return null;
			}
			int length = rain.size();
			int size = interval / 3;
			
			for (int i = 0; i < length / size; i++)
			{
				result.put((i + 1) * interval, this.snow(rain.subList(i * size, (i + 1) * size) , pph.subList(i * size, (i + 1) * size) , snowObject));
			}
		}
		catch (Exception e)
		{
			logger.error("Snow transform to weather phenomena exception , this exception is : " + e);
		}
		
		return result;
	}
	/**
	 * 
	 * @Description: 降雪
	 * 
	 * @return Integer
	 * @throws
	 */
	private Integer snow(List<Float> rains, List<Float> pphs,List<UniObject> snowObject)
	{
		int code = 999;
		try
		{
			//计算段时间内相态为3(固态)的总降水量
			float sumRain = 0.0f; 
			for (int i = 0; i < pphs.size(); i++)
			{
				if (pphs.get(i) == 3)
				{
					sumRain += rains.get(i);
				}
			}
			if (!(sumRain > 0.0f))
			{
				return code;
			}
			//根据降水量判断雪的量级
			for (UniObject sObject : snowObject)
			{
				String[] statandar = sObject.getStringValue("statandar").split("-");
				float min = Float.valueOf(statandar[0]);
				float max = Float.valueOf(statandar[1]);
				
				if (sumRain >= min && sumRain < max)
				{
					code = sObject.getIntegerValue("code");
					break;
				}
				
			}
		}
		catch (Exception e)
		{
			logger.error("Singn valid Snow transform to weather phenomena exception , this exception is : " + e);
		}
		
		return code;
	}
	/**
	 * 
	 * @Description: 雨夹雪
	 * @param rain 降水数据
	 * @param pph 
	 * @return Map<Integer,Integer>
	 * @throws
	 */
	private Map<Integer, Integer> sleet(List<Float> rain, List<Float> pph , int interval)
	{
		Map<Integer, Integer> result = null;
		
		try
		{
			result = new HashMap<Integer, Integer>();
			if(rain == null || pph == null)
			{
				logger.error("Rain or PPh data is null.");
				return null;
			}
			
			int length = rain.size();
			int size = interval / 3;
			
			for (int i = 0; i < length / size ; i++)
			{
				result.put((i + 1) * interval, this.sleet(rain.subList(i * size, ( i + 1) * size), pph.subList(i * size, ( i + 1) * size)));
			}
		}
		catch (Exception e)
		{
			logger.error("Sleet transform to weather phenomena exception , this exception is : " + e);
		}
		
		return result;
	}
	/**
	 * 
	 * @Description: 单时效雨夹雪判断
	 * 说明：12小时内1个以上时段出现降水且相态为2 或者 至少2个以上时段出现降水且降水时段相态分别为1和3
	 * @return Integer
	 * @throws
	 */
	private Integer sleet(List<Float> rains, List<Float> pphs)
	{
		int code = 999;
		//判断单时效出现降水且相态为2(混合态) 使用 “2”表示
		//判断单时效出现降水且相态为1(液态) 使用“1”表示
		//判断单时效出现降水且相态为3(固态) 使用“3”表示
		//其他情况使用“0”表示
		try
		{
			List<Integer> resultList = new ArrayList<Integer>();
			for (int i = 0; i < rains.size(); i++)
			{
				//1个时段有降水 且降水相态为 2(混合态)
				if (rains.get(i) > 0.0f && pphs.get(i) == 2)
				{
					resultList.add(2);
				}
				else if (rains.get(i) > 0.0f && pphs.get(i) == 1)
				{
					resultList.add(1);
				} else if (rains.get(i) > 0.0f && pphs.get(i) == 3)
				{
					resultList.add(3);
				}
				else{
					resultList.add(0);
				}
			}
			
			//判断一段时间的天气情况
			if (resultList.contains(2) || ((resultList.contains(1) && resultList.contains(3))))
			{
				code = 6;
			}
		}
		catch (Exception e)
		{
			logger.error("Single valid Sleet transform to weather phenomena exception , this exception is : " + e);
		}
		
		return code;
	}
	/**
	 * 
	 * @Description: 雷阵雨判断
	 * 说明：该点12小时内任意时段降水量大于0.0 且降水时段雷暴编码为4
	 * @return Map<String,Integer>
	 * @throws
	 */
	private Map<Integer, Integer> thunderShower(List<Float> rain, List<Float> ssm, List<Float> hail , int interval)
	{
		Map<Integer, Integer> result = null;//new HashMap<Integer, Integer>();
		try
		{
			result = new HashMap<Integer, Integer>();
			if (rain == null || ssm == null || hail == null)
			{
				logger.error("Rain or ssm or hail data is null.");
				return null;
			}
			int length = rain.size();
			int size = interval / 3;
			for (int i = 0; i < length / size ; i++)
			{
				result.put((i + 1) * interval, this.thunderShower(rain.subList(i * size, ( i + 1) * size), ssm.subList(i * size, ( i + 1) * size) , hail.subList(i * size, ( i + 1) * size)));
			}
		}
		catch (Exception e)
		{
			logger.error("SSM transform to weather phenomena exception , this exception is : " + e);
		}
		
		return result;
	}
	/**
	 * 
	 * @Description: 判断单个时效是否为雷阵雨 且是否伴随冰雹出现
	 * @param rains 降水数据
	 * @param ssms 雷暴数据
	 * @param hail 冰雹数据
	 * @return Integer
	 * @throws
	 */
	private Integer thunderShower(List<Float> rains, List<Float> ssms , List<Float> hail)
	{
		
		//这里自定义 
		//判断出是雷阵雨使用 "1"来表示
		//判断出是雷阵雨加冰雹 使用"2"来表示
		//判断出其他的使用999表示无效
		int code = 999;
		try
		{
			List<Integer> resultList = new ArrayList<Integer>();
			for (int i = 0; i < rains.size(); i++)
			{
				if (rains.get(i) > 0.0f && ssms.get(i) == 4)
				{
					//进入判断说明已经是雷阵雨,再来判断冰雹
					if (hail.get(i) == 5){
						resultList.add(2);
					}
					else {
						resultList.add(1);
					}
				}else {
					resultList.add(-1);
				}
			}
			
			if (resultList.contains(2))
			{
				code = 5;
			}
			else if(resultList.contains(1)){
				code = 4;
			}
			else {
				code = 999;
			}
		}
		catch (Exception e)
		{
			logger.error("Single valid SSM transform to weather phenomena exception , this exception is : " + e);
		}
		
		return code;
	}
	/**
	 * @param interval 
	 * 
	 * @Description: 12小时降水情况
	 * @return Map<Integer,Integer>
	 * @throws
	 */
	private Map<Integer, Integer> rain(List<Float> rain, List<Float> pph , List<UniObject> rainObject, int interval)
	{
		Map<Integer, Integer> rainAndValid = null;//new HashMap<Integer, Integer>();
		try
		{
			rainAndValid = new HashMap<Integer, Integer>();
			if (rain == null || pph == null || rainObject == null)
			{
				logger.error("Rain or pph or rainObject param is null.");
				return null;
			}
			int length = rain.size();
			Map<Integer, Float> sumRain = new HashMap<Integer, Float>();
			int size = interval / 3;
			for (int i = 0; i < length / size; i++)
			{
				sumRain.put((i + 1) * interval, this.sum(rain.subList(i * size , (i + 1) * size)));
			}
			
			rainAndValid = rain(sumRain , rain , pph , rainObject , interval);
		}
		catch (Exception e)
		{
			logger.error("Precipitation transform to weather phenomena exception , this exception is : " + e);
		}
		
		return rainAndValid;
	}
	/**
	 * 
	 * @Description: 12小时累计降水量和各个时效降水量和相态判断
	 * @return Map<Integer,Integer>
	 * @throws
	 */
	private Map<Integer, Integer> rain(Map<Integer, Float> sumRains, List<Float> rain, List<Float> pph,  List<UniObject> rainObject, int interval)
	{	
		Map<Integer, Integer > map = null;//new HashMap<Integer, Integer>();
		try
		{
			map = new HashMap<Integer, Integer>();
			if (rain == null || pph == null || rainObject == null)
			{
				logger.error("Rain or pph or rainObject param is null.");
				return null;
			}
			//获取降水标准参数
			List<UniObject> statandarParam = new ArrayList<UniObject>();
			for (UniObject u : rainObject)
			{
				if(u.getIntegerValue("statandarInterval") == interval)
				{
					statandarParam.add(u);
				}
			}
			
			int index = sumRains.size();
			for (Integer valid : sumRains.keySet())
			{
				index--;
				float sumRain = sumRains.get(valid);
				if (sumRain > 0.0f)
				{
					for (UniObject param : statandarParam)
					{
						String[] statand = param.getStringValue("statandar").split("-");
						float min = Float.valueOf(statand[0]);
						float max = Float.valueOf(statand[1]);
						
						//判断小中大雨
						if (sumRain >= min && sumRain <= max && this.rain(rain.subList(index * (interval / 3), (index + 1) * (interval / 3)) , pph.subList(index * (interval / 3), (index + 1) * (interval / 3))))
						{
							map.put(valid, param.getIntegerValue("code"));
							break;
						}
						else {
							map.put(valid, 999);
						}
					}
				}
				else {
					map.put(valid, 999);
				}
			}
		}
		catch (Exception e)
		{
			logger.error("Precipitation transform to weather phenomena exception , this exception is : " + e);
		}
		
		return map;
	}
	/**
	 * 
	 * @Description: 判断降水和相态是否匹配
	 * @return boolean
	 * @throws
	 */
	private boolean rain(List<Float> rains, List<Float> pphs)
	{
		boolean flag = true;
		try
		{
			List<Boolean> isList = new ArrayList<Boolean>();
			for (int i =0 ; i < rains.size() ; i ++)
			{
				if (rains.get(i) > 0f && pphs.get(i) == 1f)
				{
					//有降水 相态为液体
					isList.add(true);
				}
				else if (rains.get(i) == 0f && (pphs.get(i) == -1f || pphs.get(i) == 0f) )
				{
					//无降水 相态没有
					isList.add(true);
				}else
				{
					isList.add(false);
				}
			}
			
			if (isList.contains(false))
			{
				flag = false;
			}
		}
		catch (Exception e)
		{
			logger.error("Singn valid precipitation transform to weather phenomena exception , this exception is : " + e);
		}
		
		return flag;
	}
	/**
	 * 
	 * @Description: 集合中所有元素求和
	 * @return Float
	 * @throws
	 */
	private Float sum(List<Float> subList)
	{
		float sum = 0.0f;
		if (subList != null)
		{
			for (int i = 0; i < subList.size(); i++)
			{
				sum += subList.get(i);
			}
		}
		return sum;
	}

	/**
	 * 
	 * @Description: 获取12小时的天气现象
	 * @return int
	 * @throws
	 */
	private Map<Integer, Integer> cloud(List<Float> etc, List<UniObject> etcParams , int interval)
	{
		Map<Integer, Integer> validAndCode = null;
		try
		{
			if (etc == null || etc.size() < 1)
			{
				logger.error("ETC data is empty.");
				return null;
			}
			if (etcParams == null || etcParams.size() < 1)
			{
				logger.error("ETC weather param is empty.");
				return null;
			}
			//获取判断云状的参数
			UniObject param = etcParams.get(0);
			String statandar = param.getStringValue("statandar");//云量判断标准
			float etcMin = Float.valueOf(statandar.split("-")[0]);
			float etcMax = Float.valueOf(statandar.split("-")[1]);
			
			validAndCode = new HashMap<Integer, Integer>();
			//把单一时效的天气现象整合成12小时的天气现象
			int length = etc.size();
			int size = interval / 3;
			for (int i = 0; i < length / size; i++)
			{
				validAndCode.put((i + 1	) * interval, this.cloud(etc.subList(i * size, (i + 1) * size) , etcMax , etcMin , size));
			}
		}
		catch (Exception e)
		{
			logger.error("ECT transform to weather phenomena exception , this exception is : " + e);
		}
		return validAndCode;
		
	}
	private Integer cloud(List<Float> etcList, float etcMax, float etcMin , int size)
	{
		//这里总云量大于 90% 使用"1" 表示
		//   总云量小于 20% 使用"2" 表示
		//   总云量大于 20% 小于90% 使用"3"表示
		int code = 999;
		try
		{
			List<Integer> result = new ArrayList<Integer>();
			for (int i = 0; i < etcList.size(); i++)
			{
				if (etcList.get(i) >= etcMax )
				{
					result.add(1);
				}
				else if (etcList.get(i) <= etcMin )
				{
					result.add(2);
				}
				else {
					result.add(3);
				}
			}
			int sum = 0;
			for (int i = 0; i < result.size(); i++)
			{
				sum += result.get(i);
			}
			if (sum == 1 * size)
			{
				code = 2; //阴
			}else if (sum == 2 * size)
			{
				code = 0; //晴
			}
			else {
				code = 1; //多云
			}
			
		}
		catch (Exception e)
		{
			logger.error("Single valid ECT transform to weather phenomena exception , this exception is : " + e);
		}
		return code;
	}

}	
